package com.efast.dmom.mgmt.service.mes.plan.impl;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import com.efast.cafe.framework.bean.ResultBean;
import com.efast.cafe.framework.jdbc.JdbcDao;
import com.efast.cafe.framework.util.SpringWebUtils;
import com.efast.dmom.mgmt.bean.mes.InfPpPlan;
import com.efast.dmom.mgmt.bean.mes.MesCalendarShiftRelation;
import com.efast.dmom.mgmt.bean.mes.plan.PlanCapacityBean;
import com.efast.dmom.mgmt.dao.mes.plan.PlanAutoScheduleDao;
import com.efast.dmom.mgmt.service.mes.plan.PlanAutoScheduleService;
import com.efast.dmom.mgmt.utils.MesConstant;
@Transactional
@Service
public class PlanAutoScheduleServiceImpl implements PlanAutoScheduleService {

	@Autowired
	PlanAutoScheduleDao planAutoScheduleDao = null;

	@Autowired
	@Qualifier("jdbcDao")
	private JdbcDao jdbcDao = null;

	private final String[] mesPlant = new String[] { MesConstant.MES_PLANT_BS, MesConstant.MES_PLANT_PS,
			MesConstant.MES_PLANT_AS };

	private final String BS_PRODUCTION_TIME_KEY = "BS_PRODUCTION_TIME";
	private final String PS_PRODUCTION_TIME_KEY = "PS_PRODUCTION_TIME";
	private final String AS_PRODUCTION_TIME_KEY = "AS_PRODUCTION_TIME";

	private int bsProductionTime = 0;
	private int psProductionTime = 0;
	private int asProductionTime = 0;

	

	@Override
	public ResultBean fixPlanOnlineDateList(List<InfPpPlan> plans) {
		ResultBean resultBean = new ResultBean(true);
		for (InfPpPlan infPpPlan : plans) {
			ResultBean fixPlanOnlineDate = fixPlanOnlineDate(infPpPlan);
			if (fixPlanOnlineDate.getMessage() != null && fixPlanOnlineDate.getMessage() != "") {
					return fixPlanOnlineDate;
			}
		}
		return resultBean;
	}
	
	
	
	
	
	@Override
	public ResultBean fixPlanOnlineDate(InfPpPlan plan) {

		ResultBean resultBean = null;

		if (plan != null) {
			
			Map<String, List<MesCalendarShiftRelation>> capacityMap = new HashMap<String, List<MesCalendarShiftRelation>>();

			List<InfPpPlan> planList = getUnBroadcastPlanList(plan.getPlanOrderNo(), plan.getFactoryCode(),
					plan.getFlagVin());
			planList.add(plan);

			resultBean = validatePlan(planList);
			if (!resultBean.isSuccess()) {
				return resultBean;
			}

			bsProductionTime = getProductionTime(BS_PRODUCTION_TIME_KEY);
			psProductionTime = getProductionTime(PS_PRODUCTION_TIME_KEY);
			asProductionTime = getProductionTime(AS_PRODUCTION_TIME_KEY);

			if (planList != null && planList.size() > 0) {

				Collections.sort(planList, InfPpPlan.offLineDateComparator);

				for (InfPpPlan target : planList) {

					// why ???? Calendar is a better choice

					Date planEarliestOnlineDate = getCurrentDate();

					planEarliestOnlineDate = getPlanOnlineDate(target, plan.getFactoryCode(), capacityMap,
							planEarliestOnlineDate, planList.get(planList.size() - 1).getPlanOfflineDate());
					if (planEarliestOnlineDate == null) {
						resultBean.setSuccess(false);
						resultBean.setMessage("由于产能不足系统无法获取计划【" + plan.getPlanOrderNo() + "】的上线时间，请检查日历产能配置");
						return resultBean;
					}

					if (planEarliestOnlineDate != null) {
						target.setPlanOnlineDate(planEarliestOnlineDate);
						target.setLastUpdateTime(new Date());
						target.setLastUpdateUser(SpringWebUtils.getRequestUser());
					}
					
					planAutoScheduleDao.updatePlanInfo(target);

					Iterator<Entry<String, List<MesCalendarShiftRelation>>> iterator = capacityMap.entrySet().iterator();

					List<MesCalendarShiftRelation> dayInfoList = new ArrayList<MesCalendarShiftRelation>();

					while (iterator.hasNext()) {

						List<MesCalendarShiftRelation> tmpList = iterator.next().getValue();
						for (MesCalendarShiftRelation dayInfo : tmpList) {
							dayInfo.setLastUpdateTime(new Date());
							dayInfo.setLastUpdateUser(SpringWebUtils.getRequestUser());
						}
						dayInfoList.addAll(tmpList);
					}

					updateCapacityInfo(dayInfoList);
				}
			}
		}
		return resultBean;
	}

	private Date getCurrentDate() {

		Date date = new Date();

		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

		try {
			date = sdf.parse(sdf.format(date));
		} catch (ParseException e) {
			// TODO Aaron
			e.printStackTrace();
		}

		return date;
	}

	private void updateCapacityInfo(List<MesCalendarShiftRelation> capacityList) {

		if (capacityList != null) {

			List<PlanCapacityBean> planCapacityList = new ArrayList<PlanCapacityBean>();

			for (MesCalendarShiftRelation capacity : capacityList) {

				List<PlanCapacityBean> pBeanList = capacity.getCapacityList();
				for (PlanCapacityBean pBean : pBeanList) {

					if (pBean.getPlanId() != 0) {

						planCapacityList.add(pBean);
					}
				}
			}
			if (planCapacityList.size() > 0) {
				planAutoScheduleDao.deleteCapabilityInfo(planCapacityList);
				planAutoScheduleDao.savePlanScheduleInfo(planCapacityList);
			}
		}
	}

	private Date getPlanOnlineDate(InfPpPlan target, String factoryCode,
			Map<String, List<MesCalendarShiftRelation>> capacityMap, Date planEarliestOnlineDate,
			Date planLatestOnlineDate) {

		Date bsOnlineDate = null;

		Date tmpPlanOnlineDate = planEarliestOnlineDate;

		for (String plant : mesPlant) {

			if (tmpPlanOnlineDate == null) {
				return null;
			}

			int productionTime = 0;

			if (MesConstant.MES_PLANT_PS.equals(plant)) {
				productionTime = bsProductionTime;
			} else if (MesConstant.MES_PLANT_AS.equals(plant)) {
				productionTime = bsProductionTime + psProductionTime;
			}

			if (bsOnlineDate != null) {
				tmpPlanOnlineDate.setDate(bsOnlineDate.getDate() + productionTime);
				if (!tmpPlanOnlineDate.before(target.getPlanOfflineDate())) {
					return null;
				}
			}
			
			List<MesCalendarShiftRelation> scheduledDayInfoList = null;
			String mapKey = target.getFactoryCode() + plant + target.getFlagVin();
			if(capacityMap.get(mapKey) == null){
				
				scheduledDayInfoList = planAutoScheduleDao.getScheduledDayInfo(
						target.getFactoryCode(), plant, target.getFlagVin(), planEarliestOnlineDate, planLatestOnlineDate);

				for (MesCalendarShiftRelation dayInfo : scheduledDayInfoList) {
					dayInfo.setScheduledCount(0);
					dayInfo.setScheduleCounter(0);
				}
				capacityMap.put(mapKey, scheduledDayInfoList);
			}
			else {
				scheduledDayInfoList = capacityMap.get(mapKey);
			}

			if (scheduledDayInfoList == null || scheduledDayInfoList.size() == 0) {
				return null;
			}

			int tmpScheduledCount = 0;
			boolean isCapacitySet = false;
			for (MesCalendarShiftRelation dayInfo : scheduledDayInfoList) {

				if (isCapacitySet || tmpScheduledCount >= target.getQty()) {
					break;
				}

				if (dayInfo.getCalendar().before(tmpPlanOnlineDate) || dayInfo.getCalendar().before(getCurrentDate())) {
					continue;
				}

				dayInfo.setScheduleCounter(dayInfo.getScheduleCounter() + getAllocatedDay(dayInfo));

				int remainder = dayInfo.getPlanInput() - dayInfo.getScheduleCounter();
				if (remainder > 0) {

					dayInfo.setPlanId(target.getId());

					if (bsOnlineDate == null) {
						bsOnlineDate = dayInfo.getCalendar();
					}

					if (remainder >= target.getQty()) {

						dayInfo.setScheduledCount(target.getQty());

						dayInfo.setScheduleCounter(dayInfo.getScheduleCounter() + target.getQty());
						tmpScheduledCount = tmpScheduledCount + target.getQty();
						// tmpPlanOnlineDate = dayInfo.getCalendar();

						isCapacitySet = true;
						break;
					} else {
						tmpScheduledCount = tmpScheduledCount + remainder;
						// dayInfo.setScheduledCount(dayInfo.getPlanInput());
						dayInfo.setScheduleCounter(dayInfo.getScheduleCounter() + remainder);
						dayInfo.setScheduledCount(remainder);
					}

					for (MesCalendarShiftRelation dayInfoNext : scheduledDayInfoList) {

						if (dayInfoNext.getCalendar().after(dayInfo.getCalendar())) {

							dayInfoNext.setScheduleCounter(
									dayInfoNext.getScheduleCounter() + getAllocatedDay(dayInfoNext));
							dayInfoNext.setPlanId(target.getId());

							int countDay = dayInfoNext.getPlanInput() - dayInfoNext.getScheduleCounter();
							if (countDay >= target.getQty() - tmpScheduledCount) {

								dayInfoNext.setScheduledCount(target.getQty() - tmpScheduledCount);
								dayInfoNext.setScheduleCounter(
										dayInfoNext.getScheduleCounter() + target.getQty() - tmpScheduledCount);

								tmpScheduledCount = target.getQty();
								isCapacitySet = true;
								// tmpPlanOnlineDate =
								// dayInfoNext.getCalendar();
								break;
							} else {
								// dayInfoNext.setScheduledCount(dayInfoNext.getPlanInput());
								dayInfoNext.setScheduleCounter(dayInfoNext.getScheduleCounter() + countDay);
								dayInfoNext.setScheduledCount(countDay);
								tmpScheduledCount = tmpScheduledCount + countDay;
							}
						}
					}
				}
			}

			if (!isCapacitySet) {
				return null;
			}

			if (MesConstant.MES_PLANT_PS.equals(plant)) {

				Date date = new Date();
				date.setDate(tmpPlanOnlineDate.getDate());
				target.setPaintPlanOnlineDate(date);
			} else if (MesConstant.MES_PLANT_AS.equals(plant)) {
				target.setFinalPlanOnlineDate(tmpPlanOnlineDate);

				Date finalPlanOfflineDate = new Date();
				finalPlanOfflineDate.setDate(tmpPlanOnlineDate.getDate() + asProductionTime);

				if (!finalPlanOfflineDate.before(target.getPlanOfflineDate())) {
					return null;
				}
			}
		}

		return bsOnlineDate;
	}

	// TODO: NOT A GOOD SOLUTION
	private int getAllocatedDay(MesCalendarShiftRelation capacityInfo) {

		int result = 0;

		if (capacityInfo == null) {
			return result;
		}
		Integer days = planAutoScheduleDao.getAllocatedDay(capacityInfo);
		result = (days == null) ? 0 : days;

		return result;
	}

	private int getProductionTime(String pKey) {

		String sql = "SELECT param_value FROM portal_base_parameter  where param_key = '" + pKey + "'";

		List<Map<String, Object>> result = jdbcDao.queryForListMap(sql);

		if (result != null && !result.isEmpty()) {

			Map<String, Object> map = result.get(0);
			Object object = map.get("param_value");
			if (object != null) {

				return Integer.valueOf(object.toString());
			}
		}

		return 0;
	}

	private ResultBean validatePlan(List<InfPpPlan> planList) {

		ResultBean resultBean = new ResultBean(true);

		for (InfPpPlan plan : planList) {

			// TODO
			if (plan == null) {
				resultBean.setSuccess(false);
				resultBean.setMessage("在系统中无此计划记录记录");
				return resultBean;
			}

			if (plan.getPlanOfflineDate() == null) {
				resultBean.setSuccess(false);
				resultBean.setMessage("请维护计划【" + plan.getPlanOrderNo() + "】的计划下线时间");
				return resultBean;
			}

			if (Integer.parseInt(MesConstant.ORDER_STATUS_AUDIT) < Integer.parseInt(plan.getPlanStatus())) {
				resultBean.setSuccess(false);
				resultBean.setMessage("计划【" + plan.getPlanOrderNo() + "】为已下发状态的计划，不可以再次进行排产");
				return resultBean;
			}

			Date offLineDate = plan.getPlanOfflineDate();
			if (new Date().after(offLineDate)) {
				resultBean.setSuccess(false);
				resultBean.setMessage("计划【" + plan.getPlanOrderNo() + "】计划下线时间早于当前时间,请重新配置计划下线时间");
				return resultBean;
			}
		}

		return resultBean;
	}

	private List<InfPpPlan> getUnBroadcastPlanList(String planOrderNo, String factoryCode, String model) {

		List<InfPpPlan> planList = new ArrayList<InfPpPlan>();

		planList = planAutoScheduleDao.getUnBroadcastPlanList(planOrderNo, factoryCode, model);

		return planList;
	}


}
